package com.pic.mgt.haishin.action;

import java.io.File;
import java.util.Date;

import org.springframework.dao.DataAccessException;

import com.pic.mgt.action.ActionException;
import com.pic.mgt.action.MessageRecoverActionImpl;
import com.pic.mgt.dao.haishin.HaishinBusinessAsgmtActionInfoBean;
import com.pic.mgt.dao.haishin.IAppointedHaishinBusinessAsgmtActionDao;
import com.pic.mgt.haishin.HaishinBusinessUnitFactory;
import com.pic.mgt.haishin.executer.AsgmtFileProcess;
import com.pic.mgt.log.IgxLog;
import com.pic.mgt.monitor.WrongUnitFormatException;
import com.pic.mgt.monitor.parser.ConfirmtaionFileForTxFileParser;
import com.pic.mgt.monitor.parser.FormatParser;
import com.pic.mgt.utils.FilePathUtils;

// (送多方修改) (多了 implement HaishinMessageRecoverAction)
public class HaishinMessageRecoverActionImpl extends MessageRecoverActionImpl implements HaishinMessageRecoverAction {
	private String haishinOutboxPathStr;
	private File haishinOutboxPath;
	private String haishinOutboxPublicStr;
	private FormatParser messageTerminalIdParser;
	private FormatParser appointedTargetMessageTransactionFileParser;
	private FormatParser haishinMessageBusinessTypeParser;
	private IAppointedHaishinBusinessAsgmtActionDao appointedHaishinBusinessAsgmtActionDao;
	
	@Override
	public synchronized boolean recoverMessage(String messageFilenameWithoutSuffix) {
		if (null == messageFilenameWithoutSuffix) {
			// ********************** Log **********************
			IgxLog.messageLog.warn(this,
							"Recovering message preprocess failed. Did not provide target filename.");
			// ********************** Log **********************
			
			return false;
		}
		
		// ********************** Log **********************
		IgxLog.messageLog.info(this,
						"Starting recover message '{}' preprocess.",
						messageFilenameWithoutSuffix);
		// ********************** Log **********************
		
		boolean isProcessRecoveryMessageSuccessful =
			processRecoveryMessage(messageFilenameWithoutSuffix);
		if (!isProcessRecoveryMessageSuccessful) {
			return false;
		}
		
		// ********************** Log **********************
		IgxLog.messageLog.info(this,
						"Recovering message '{}' preprocess completed.",
						messageFilenameWithoutSuffix);
		// ********************** Log **********************
		
		return true;
	}
	
	public boolean processRecoveryMessage(String messageFilenameWithoutSuffix) {
		if (null == messageFilenameWithoutSuffix || messageFilenameWithoutSuffix.isEmpty()) {
			// ********************** Log **********************
			IgxLog.messageLog.warn(this,
							"Recovering message failed. Did not provide transaction file name.");
			// ********************** Log **********************
			
			return false;
		}
		
		// 取得端末 id
		String terminalId = null;
		try {
			terminalId = (String)this.messageTerminalIdParser.parse(messageFilenameWithoutSuffix);
		} catch (WrongUnitFormatException e) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e.getMessage());
			// ********************** Log **********************
			
			// ********************** Log **********************
			IgxLog.messageLog.error(this,
					"SUDA-220 Recovering message '{}' preprocess can't parse the terminal id of the message.",
					messageFilenameWithoutSuffix);
			// ********************** Log **********************
			return false;
		}
		
		// 取得配信訊息的業務型態 
		String haishinMessageBusinessType = null;
		try {
			haishinMessageBusinessType = (String)this.haishinMessageBusinessTypeParser.parse(messageFilenameWithoutSuffix);
		} catch (WrongUnitFormatException e1) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e1.getMessage());
			// ********************** Log **********************

			// ********************** Log **********************
			IgxLog.messageLog.error(this,
					"SUDA-221 Recovering message '{}' preprocess can't parse the business type of the message.",
					messageFilenameWithoutSuffix);
			// ********************** Log **********************
			
			return false;
		}
		
		// 取得位於訊息目錄下的相關檔案
		
		File[] messageRelatedFiles;
		try {
			messageRelatedFiles = getMessageRelatedFiles(messageFilenameWithoutSuffix, terminalId, haishinMessageBusinessType);
		} catch (ActionException e) {
			return false;
		}
		// 交易檔
		File transactionFile = messageRelatedFiles[0];
		// 交易檔的確認檔
		File confirmationFileForTxFile = messageRelatedFiles[1];
		// 訊息的確認檔
		File confirmationFileForMsgFile = messageRelatedFiles[2];
		
		if (haishinMessageBusinessType.equals(HaishinBusinessUnitFactory.APPINTED_HAISHIN)) {
			// 表示交易的對象是共用的檔案(指示配信,端末0000000000底下的),直接讓 message 被 redetect
			boolean isRedetectFileSuccessful =
				super.redetectFile(transactionFile, confirmationFileForMsgFile);
			if (!isRedetectFileSuccessful) {
				return false;
			}
		}
		else {
			// 表示交易的對象不是共用的檔案，要做額外的判斷。
			boolean isCheckAndDoRecoverActionSuccessful =
					super.checkAndDoRecoverAction(transactionFile,
												  confirmationFileForTxFile,
												  confirmationFileForMsgFile);
			if (!isCheckAndDoRecoverActionSuccessful) {
				return false;
			}
		}
		
		return true;
	}
			
	/**
	 * 取得交易訊息的相關檔案
	 * @param messageFilenameWithoutSuffix
	 * @return [0] transactionFile ; [1] confirmationFileForTxFile ; [2] confirmationFileForMsgFile
	 */
	private File[] getMessageRelatedFiles(String messageFilenameWithoutSuffix, String terminalId, String haishinMessageBusinessType) throws ActionException {
		// 取得位於訊息目錄下的交易檔 和 訊息確認檔
		File transactionFile = null;
		File confirmationFileForMsgFile = null;
		if (haishinMessageBusinessType.equals(HaishinBusinessUnitFactory.APPINTED_HAISHIN)) {
			// 指示配信交易
			// 交易的是指示配信解出來的檔案(位於Haishin Outbox Public資料匣底下的)
			
			// 訊息確認檔
			confirmationFileForMsgFile = FilePathUtils.multiPathConcat(
										this.haishinOutboxPath.getAbsolutePath(),
										this.haishinOutboxPublicStr,
										messageFilenameWithoutSuffix + super.messageConfirmationFilenameSuffix);
			
			try {
				// 交易檔
				transactionFile = (File)
								  this.appointedTargetMessageTransactionFileParser.parse(confirmationFileForMsgFile);
			} catch (WrongUnitFormatException e) {
				// ********************** Log **********************
				IgxLog.messageDetailsLog.error(this, e.getMessage());
				// ********************** Log **********************
				
				// ********************** Log **********************
				IgxLog.messageLog.error(this,
						"SUDA-222 Recovering message '{}' preprocess can't parse the transaction file of the message.",
						messageFilenameWithoutSuffix);
				// ********************** Log **********************
				
				throw new ActionException("");
			}
		}
		else if (haishinMessageBusinessType.equals(AsgmtFileProcess.typeCharForAsgmtFilename) ||
				 haishinMessageBusinessType.equals(HaishinBusinessUnitFactory.GENERAL_HAISHIN)) {
			// 指示配信交易(交易的是指示配信的指示檔案) 或 一般配信交易
			
			// 訊息確認檔
			confirmationFileForMsgFile = FilePathUtils.multiPathConcat(
										this.haishinOutboxPath.getAbsolutePath(),
										terminalId,
										messageFilenameWithoutSuffix + super.messageConfirmationFilenameSuffix);
			
			// 交易檔
			transactionFile = FilePathUtils.multiPathConcat(this.haishinOutboxPath.getAbsolutePath(),
															terminalId,
															messageFilenameWithoutSuffix);
		}
		else {
			// 找不到符合的配信業務類別
			
			// ********************** Log **********************
			IgxLog.messageLog.error(this,
					"SUDA-223 Recovering message '{}' preprocess can't identify the business type '{}' of the message.",
					messageFilenameWithoutSuffix, haishinMessageBusinessType);
			// ********************** Log **********************
			
			throw new ActionException("");
		}
		
		// 取得位於訊息目錄下交易檔的確認檔
		File confirmationFileForTxFile = ConfirmtaionFileForTxFileParser.getConfirmationFile(transactionFile);
		
		return new File[] {transactionFile,
						   confirmationFileForTxFile,
						   confirmationFileForMsgFile};
	}
	
	@Override
	/*
	 * 覆寫掉 MessageRecoverActionImpl 的方法。因為在配信中，有分為一般和指示配信，
	 * 其中一般配信的交易檔同樣是存在於 business_target_action table中，但而指示配信
	 * 的指示檔交易記錄是存在於 apponited_haishin_business_asgmt_action table 中。
	 */
	protected Date[] getTransactionFileTimeInfo(File transactionFile)
			throws DataAccessException {
		// 取得配信訊息的業務型態 
		String haishinMessageBusinessType = null;
		try {
			haishinMessageBusinessType = (String)this.haishinMessageBusinessTypeParser.parse(transactionFile.getName());
		} catch (WrongUnitFormatException e1) {
			// 錯誤可以不用理會，因為先前的步驟中已做過分析，若有錯不會做到這。
		}
		
		if (haishinMessageBusinessType.equals(HaishinBusinessUnitFactory.APPINTED_HAISHIN)||
			haishinMessageBusinessType.equals(HaishinBusinessUnitFactory.GENERAL_HAISHIN)) {
			// 表示交易的對象是指示配信的共用的檔案或一般配信的檔案
			return super.getTransactionFileTimeInfo(transactionFile);
		}
		else {
			// 表示交易的對象指示配信的交易檔(記錄存在於apponited_haishin_business_asgmt_action table 中)
			HaishinBusinessAsgmtActionInfoBean haishinBusinessAsgmtActionInfoBean = 
					this.appointedHaishinBusinessAsgmtActionDao.findHaishinBasicBusinessAsgmtActionInfoByAsgmtFilename(transactionFile.getName());
			if (null == haishinBusinessAsgmtActionInfoBean) {
				return null;
			}
			else {
				return new Date[] {haishinBusinessAsgmtActionInfoBean.getCreatingTime(),
								   haishinBusinessAsgmtActionInfoBean.getLastTransactionTime()};
			}
		}
	}
	
	// --- getter and setter ---
	
	public void setMessageTerminalIdParser(FormatParser messageTerminalIdParser) {
		this.messageTerminalIdParser = messageTerminalIdParser;
	}

	public void setHaishinOutboxPathStr(String haishinOutboxPathStr) {
		this.haishinOutboxPathStr = haishinOutboxPathStr;
		this.haishinOutboxPath = new File(haishinOutboxPathStr);
	}

	public void setHaishinOutboxPublicStr(String haishinOutboxPublicStr) {
		this.haishinOutboxPublicStr = haishinOutboxPublicStr;
	}

	public void setAppointedTargetMessageTransactionFileParser(
			FormatParser appointedTargetMessageTransactionFileParser) {
		this.appointedTargetMessageTransactionFileParser = appointedTargetMessageTransactionFileParser;
	}

	public void setHaishinMessageBusinessTypeParser(
			FormatParser haishinMessageBusinessTypeParser) {
		this.haishinMessageBusinessTypeParser = haishinMessageBusinessTypeParser;
	}

	public void setAppointedHaishinBusinessAsgmtActionDao(
			IAppointedHaishinBusinessAsgmtActionDao appointedHaishinBusinessAsgmtActionDao) {
		this.appointedHaishinBusinessAsgmtActionDao = appointedHaishinBusinessAsgmtActionDao;
	}
}
